package bot.module.equity;

import static util.GameTypeInt.*;

import org.pokersource.enumerate.BeliefVector;
import org.pokersource.enumerate.HoldemBeliefVector;
import org.pokersource.enumerate.SAIE;
import org.pokersource.game.Deck;

import util.DebugOut;
import game.model.Card;

/**
 * This class weights the odds of the pot size to the needed call size against the odds of winning the hand.</br>
 * @author Witthold/Korol
 */
public class SubjectiveAllinEquity implements IF_Equity {
	
	private int gameType;
	private int maxBoardCards;
	
	public SubjectiveAllinEquity(int gameType, int maxBoardCards) {
		
		DebugOut.showVerbosePotEquity("new default PotEquity object");

		this.gameType = gameType;
		this.maxBoardCards = maxBoardCards;
	}

	// TODO implement a possibility to specify hand distributions for hole cards
	@Override
	public double[] getEquity(int numHoleSamples, int numBoardSamples, Card[][] holeCards_in, Card[] boardCards_in, Card[] deadCards_in) {

		double[] ev = new double[holeCards_in.length];

		BeliefVector[] holeCards = new BeliefVector[holeCards_in.length]; 
		
		long boardCards;
		long deadCards;

		for (int i = 0; i < holeCards_in.length; i++) {

			if(holeCards_in[i] != null) {
				holeCards[i] = getBeliefVector(holeCards_in[i][0].toString() + holeCards_in[i][1].toString());
				
			} else {
				DebugOut.showVerbosePotEquity("Player " + i + ": any hand distribution");
				holeCards[i] = getBeliefVector("<any>");
			}
		}
		
		if( boardCards_in != null ) {

			StringBuffer strBuffer = new StringBuffer();

			for (int i = 0; i < boardCards_in.length; i++) {

				strBuffer.append(boardCards_in[i].toString());
			}
			boardCards = Deck.parseCardMask(strBuffer.toString());
		
		} else {

			boardCards = 0;
		}

		if( deadCards_in != null ) {

			StringBuffer strBuffer = new StringBuffer();

			for (int i = 0; i < deadCards_in.length; i++) {

				strBuffer.append(deadCards_in[i].toString());
			}
			deadCards = Deck.parseCardMask(strBuffer.toString());
		} else {

			deadCards = 0;
		}

		try {

			/* if all board cards are revealed, there can't be used Monte Carlo simulation. */
			if(boardCards_in.length == maxBoardCards) {
				numBoardSamples = 0;
			}
			
			// TODO if enemy hand distribution are very specific reduce numHoleSamples (or use full enumeration)
			
			SAIE.FlopGameSAIE(gameType, numHoleSamples, numBoardSamples, holeCards, boardCards, deadCards, ev, null, null);	// TODO use the last two parameters too?
			
		} catch (Exception e) {
			System.out.println("In Java: caught exception: " + e);
			e.printStackTrace();
		}

		for (Card[] cards : holeCards_in) {

			DebugOut.showVerbosePotEquity("Hole cards: ");

			if (cards != null) {

				for (Card card : cards) {

					DebugOut.showVerbosePotEquity(card.toString() + " ");
				}
			}
			DebugOut.showVerbosePotEquity("");
		}
		
		DebugOut.showVerbosePotEquity("Board cards: ");
		
		for (Card card : boardCards_in) {
		
			DebugOut.showVerbosePotEquity(card.toString() );
		}
		DebugOut.showVerbosePotEquity("");

		DebugOut.showVerbosePotEquity("Pot subjectiveAllinEquity: " + ev[0]);

		return ev;
	}

	/**
	 * Returns the BeliefVector for the given string depending on the game type.</br>
	 * Only texas holdem BeliefVectors are implemented yet.
	 * @param string The string describing the believed cards of the player.
	 * @return The BeliefVector for the game type
	 */
	private BeliefVector getBeliefVector(String string) {

		switch (gameType) {
		case GAME_HOLDEM:
			return new HoldemBeliefVector(string);
		
		case GAME_HOLDEM8:
			return new HoldemBeliefVector(string);
			
		case GAME_OMAHA:
		case GAME_OMAHA8:
		case GAME_7STUD:
		case GAME_7STUD8:
		case GAME_7STUDNSQ:
		case GAME_RAZZ:
		case GAME_5DRAW:
		case GAME_5DRAW8:
		case GAME_5DRAWNSQ:
		case GAME_LOWBALL:
		case GAME_LOWBALL27:
		
		default:
			return null;
		}
	}
}
